home *** CD-ROM | disk | FTP | other *** search
/ Aminet 32 / Aminet 32 (1999)(Schatztruhe)[!][Aug 1999].iso / Aminet / dev / lang / Python152.lha / Python-1.5 / Demo / metaclasses / Trace.py < prev   
Text File  |  1998-09-14  |  4KB  |  146 lines

  1. """Tracing metaclass.
  2.  
  3. XXX This is very much a work in progress.
  4.  
  5. """
  6.  
  7. import types, sys
  8.  
  9. class TraceMetaClass:
  10.     """Metaclass for tracing.
  11.  
  12.     Classes defined using this metaclass have an automatic tracing
  13.     feature -- by setting the __trace_output__ instance (or class)
  14.     variable to a file object, trace messages about all calls are
  15.     written to the file.  The trace formatting can be changed by
  16.     defining a suitable __trace_call__ method.
  17.  
  18.     """
  19.  
  20.     __inited = 0
  21.  
  22.     def __init__(self, name, bases, dict):
  23.         self.__name__ = name
  24.         self.__bases__ = bases
  25.         self.__dict = dict
  26.         # XXX Can't define __dict__, alas
  27.         self.__inited = 1
  28.  
  29.     def __getattr__(self, name):
  30.         try:
  31.             return self.__dict[name]
  32.         except KeyError:
  33.             for base in self.__bases__:
  34.                 try:
  35.                     return base.__getattr__(name)
  36.                 except AttributeError:
  37.                     pass
  38.             raise AttributeError, name
  39.  
  40.     def __setattr__(self, name, value):
  41.         if not self.__inited:
  42.             self.__dict__[name] = value
  43.         else:
  44.             self.__dict[name] = value
  45.  
  46.     def __call__(self, *args, **kw):
  47.         inst = TracingInstance()
  48.         inst.__meta_init__(self)
  49.         try:
  50.             init = inst.__getattr__('__init__')
  51.         except AttributeError:
  52.             init = lambda: None
  53.         apply(init, args, kw)
  54.         return inst
  55.  
  56.     __trace_output__ = None
  57.  
  58. class TracingInstance:
  59.     """Helper class to represent an instance of a tracing class."""
  60.  
  61.     def __trace_call__(self, fp, fmt, *args):
  62.         fp.write((fmt+'\n') % args)
  63.  
  64.     def __meta_init__(self, klass):
  65.         self.__class = klass
  66.  
  67.     def __getattr__(self, name):
  68.         # Invoked for any attr not in the instance's __dict__
  69.         try:
  70.             raw = self.__class.__getattr__(name)
  71.         except AttributeError:
  72.             raise AttributeError, name
  73.         if type(raw) != types.FunctionType:
  74.             return raw
  75.         # It's a function
  76.         fullname = self.__class.__name__ + "." + name
  77.         if not self.__trace_output__ or name == '__trace_call__':
  78.             return NotTracingWrapper(fullname, raw, self)
  79.         else:
  80.             return TracingWrapper(fullname, raw, self)
  81.  
  82. class NotTracingWrapper:
  83.     def __init__(self, name, func, inst):
  84.         self.__name__ = name
  85.         self.func = func
  86.         self.inst = inst
  87.     def __call__(self, *args, **kw):
  88.         return apply(self.func, (self.inst,) + args, kw)
  89.  
  90. class TracingWrapper(NotTracingWrapper):
  91.     def __call__(self, *args, **kw):
  92.         self.inst.__trace_call__(self.inst.__trace_output__,
  93.                                  "calling %s, inst=%s, args=%s, kw=%s",
  94.                                  self.__name__, self.inst, args, kw)
  95.         try:
  96.             rv = apply(self.func, (self.inst,) + args, kw)
  97.         except:
  98.             t, v, tb = sys.exc_info()
  99.             self.inst.__trace_call__(self.inst.__trace_output__,
  100.                                      "returning from %s with exception %s: %s",
  101.                                      self.__name__, t, v)
  102.             raise t, v, tb
  103.         else:
  104.             self.inst.__trace_call__(self.inst.__trace_output__,
  105.                                      "returning from %s with value %s",
  106.                                      self.__name__, rv)
  107.             return rv
  108.  
  109. Traced = TraceMetaClass('Traced', (), {'__trace_output__': None})
  110.  
  111.  
  112. def _test():
  113.     global C, D
  114.     class C(Traced):
  115.         def __init__(self, x=0): self.x = x
  116.         def m1(self, x): self.x = x
  117.         def m2(self, y): return self.x + y
  118.         __trace_output__ = sys.stdout
  119.     class D(C):
  120.         def m2(self, y): print "D.m2(%s)" % `y`; return C.m2(self, y)
  121.         __trace_output__ = None
  122.     x = C(4321)
  123.     print x
  124.     print x.x
  125.     print x.m1(100)
  126.     print x.m1(10)
  127.     print x.m2(33)
  128.     print x.m1(5)
  129.     print x.m2(4000)
  130.     print x.x
  131.  
  132.     print C.__init__
  133.     print C.m2
  134.     print D.__init__
  135.     print D.m2
  136.  
  137.     y = D()
  138.     print y
  139.     print y.m1(10)
  140.     print y.m2(100)
  141.     print y.x
  142.  
  143. if __name__ == '__main__':
  144.     _test()
  145.  
  146.